﻿/*
* 创建者：LIYINFAI
* 创建时间：2023/10/24 9:35:26
* 描述：
* --------------------------------------
* 修改说明：
* --------------------------------------
*/
using CommonLibrary;
using CommonLibrary.Forms;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using SCADA.BLL;
using SixLabors.Fonts.Tables.AdvancedTypographic;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;
using static NPOI.HSSF.Util.HSSFColor;

namespace SCADA
{
    /// <summary>
    /// 主界面
    /// </summary>
    public partial class FormMain : HWFrmWithTitle
    {
        /// <summary>
        /// 显示当前时间计时器
        /// </summary>
        private DispatcherTimer mDispatcherTimer = new DispatcherTimer();
        /// <summary>
        /// 窗体前置
        /// </summary>
        /// <param name="hwnd">窗体句柄</param>
        /// <returns></returns>
        [DllImport("user32")]
        static extern int SetForegroundWindow(IntPtr hwnd);
        /// <summary>
        /// 获取前置窗体句柄
        /// </summary>
        /// <returns>前置窗体句柄</returns>
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        /// <summary>
        /// 界面更新的互斥量
        /// </summary>
        private Mutex mShowAndUpdateMutex = new Mutex(false);
        /// <summary>
        /// APP PLC 交互地址
        /// </summary>
        AppPLCSetting mAppParam = AppPLCSetting.Instance(true);
        /// <summary>
        /// 判断主窗体是否打开
        /// </summary>
        public bool IsFormMain = false;
        /// <summary>
        /// 界面初始化是否完成
        /// </summary>
        public bool isFormMainLoadUnit = false;
        /// <summary>
        /// PLC连接状态
        /// </summary>
        public bool plcConnect = false;
        /// <summary>
        /// 氦检仪连接状态列表
        /// </summary>
        public List<bool> heliumConnectList = new List<bool>();
        /// <summary>
        /// 其他设备连接状态列表
        /// </summary>
        public List<bool> otherConnectList = new List<bool>();
        /// <summary>
        /// 鼠标最后位置X
        /// </summary>
        private int mMouseX = 0;
        /// <summary>
        /// 鼠标最后位置Y
        /// </summary>
        private int mMouseY = 0;
        /// <summary>
        /// 鼠标最后位置记录时间
        /// </summary>
        private DateTime mLastMouseTime = DateTime.Now;
        /// <summary>
        /// 注销时间
        /// </summary>
        private const int LOGOUT_TIMES = 180;
        /// <summary>
        /// 子窗体
        /// </summary>
        private Form mModalForm = null;
        /// <summary>
        /// 该子窗体是否有权限判断
        /// </summary>
        private bool mIsPermissionForm = false;
        /// <summary>
        /// 处理鼠标的计时器
        /// </summary>
        private System.Windows.Forms.Timer mMouseTimer = null;
        /// <summary>
        /// 初始化当前时间的计时器
        /// </summary>
        private void InitDispatcherTimer()
        {
            this.mDispatcherTimer.Tick += new EventHandler(Timer_Tick);
            this.mDispatcherTimer.IsEnabled = true;
            this.mDispatcherTimer.Interval = TimeSpan.FromSeconds(1);
            this.mDispatcherTimer.Start();
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public FormMain()
        {
            InitializeComponent();
            _instance = this;

            PluginManager.UpdateAppIcon += UpdateLogo;
            PluginManager.UpdateAppVersion += UpdateVersion;
            InitDispatcherTimer();
            this.buttonStart.Font = new Font(FontHelper.GetFont(), 20, FontStyle.Bold);
            this.buttonStart.Text = $"{FontHelper.START} 启动";
            this.buttonStart.ForeColor = Color.Green;
            this.pic_Runing.Image = CommonLibrary.Resources.Resource.ball_yellow;
            CheckForIllegalCrossThreadCalls = false;//解决线程间操作无效
            if (!HslCommunicationReg.Reg())
            {
                LogHelper.Error(null, "激活失败，当前功能只能使用8个小时！");
                return;   // 激活失败应该退出系统
            }
            APPInstance.AppInstanceShowMESMessageInListView = (message, color) =>
            {
                AddMESViewLog(color, message);
            };
            APPInstance.AppInstanceShowMessageInListView = (message, color) =>
            {
                AddRunningViewLog(color, message);
            };
            APPInstance.AppInstanceShowErrorMessageInListView = (message, color) =>
            {
                AddErrorViewLog(color, message);
            };
            APPInstance.NotifyModbusHelpersRecieve = (tag, datas) =>
            {
                //tag -> 电表
                //E 电能
                //IrAt 电流变比
                //UrAt 电压变比
                var elec = "";
                if (datas != null && datas.ContainsKey("E") && !string.IsNullOrWhiteSpace(datas["E"].ToString()))
                {
                    elec = datas["E"].ToString();
                }
                if (!string.IsNullOrWhiteSpace(elec))
                {
                    elec = $"电能：{elec} kWh";
                }
                else
                {
                    elec = "";
                }
                this.toolStripStatusLabelElec.Text = elec;
            };
            this.Icon = Program.ICON;
            LoadMenuImages();
            this.mMouseTimer = new System.Windows.Forms.Timer();
            this.mMouseTimer.Tick += MouseTimer_Tick;
            this.mMouseTimer.Interval = 1000;
            this.mMouseTimer.Start();
            ReadProductCountThread();
            InitPercentChart();
        }
        /// <summary>
        /// 更新鼠标动作的最后时间
        /// </summary>
        public void UpdateMouseTime()
        {
            this.mLastMouseTime = DateTime.Now;
        }
        /// <summary>
        /// 记录鼠标位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MouseTimer_Tick(object sender, EventArgs e)
        {
            var clientPoint = this.PointToClient(MousePosition);
            var xClient = clientPoint.X;
            var yClient = clientPoint.Y;
            var width = this.Size.Width;
            var height = this.Size.Height;
            DateTime now = DateTime.Now;
            if (xClient >= 0 && xClient <= width
                && yClient >= 0 && yClient <= height)
            {
                var handle = GetForegroundWindow().ToInt64();
                if (handle.Equals(this.Handle.ToInt64()) || (this.mModalForm != null && this.mModalForm.Handle.ToInt64().Equals(handle)))
                {
                    if (xClient != this.mMouseX && yClient != this.mMouseY
                        && now.Subtract(this.mLastMouseTime).TotalSeconds <= LOGOUT_TIMES)
                    {
                        this.mLastMouseTime = DateTime.Now;
                        this.mMouseX = xClient;
                        this.mMouseY = yClient;
                    }
                }
            }
            if (now.Subtract(this.mLastMouseTime).TotalSeconds > LOGOUT_TIMES && UserHelper.LoginUser != null && UserHelper.LoginUser.Id > 0)
            {
                Logout();
            }
            UpdateLogoutTimes();
        }
        /// <summary>
        /// 显示子窗体
        /// </summary>
        /// <param name="form">子窗体</param>
        /// <param name="PermissionForm">是否需要检验权限</param>
        private DialogResult ShowChildForm(Form form, bool PermissionForm = true)
        {
            DialogResult result = DialogResult.None;
            this.mIsPermissionForm = PermissionForm;
            this.mModalForm = form;
            result = this.mModalForm.ShowDialog(this);
            this.mModalForm = null;
            return result;
        }
        /// <summary>
        /// 登录
        /// </summary>
        private void LoginOperation()
        {
            ShowChildForm(new FormLogin(), false);
        }
        /// <summary>
        /// 检查权限动作
        /// </summary>
        /// <param name="permission">权限</param>
        /// <param name="permissionAction">动作</param>
        private void CheckPermissionAction(int permission, Action permissionAction = null)
        {
            if (UserHelper.CheckPermission(this, permission))
            {
                if (permissionAction != null)
                {
                    this.Invoke(permissionAction);
                }
            }
            else
            {
                if (UserHelper.LoginUser == null || UserHelper.LoginUser.Id <= 0)
                {
                    LoginOperation();
                    if (UserHelper.LoginUser != null && UserHelper.LoginUser.Id > 0 && UserHelper.CheckPermission(this, permission) && permissionAction != null)
                    {
                        this.Invoke(permissionAction);
                    }
                }
            }
        }
        /// <summary>
        /// 加载登录用户信息
        /// </summary>
        public void LoadUser()
        {
            if (this.statusStrip.InvokeRequired)
            {
                this.statusStrip.Invoke(new Action(() =>
                {
                    LoadUser();
                }));
            }
            else
            {
                string userName = UserHelper.LoginUser != null ? $"{UserHelper.LoginUser.UserName}({UserHelper.LoginUser.YGBH})" : "";
                string permission = UserHelper.LoginUser != null ? CommonHelper.GetEnumDescription(CommonHelper.GetEnumByRealValue(UserHelper.LoginUser.Permission, EPower.OPT)) : "";
                this.toolStripStatusLabelUserName.Text = userName;
                this.toolStripStatusLabelPermission.Text = permission;
            }
        }
        /// <summary>
        /// 用户注销
        /// </summary>
        private void Logout()
        {
            UserHelper.Logout();
            LoadUser();
            if (this.mModalForm != null && this.mIsPermissionForm)
            {
                this.mModalForm.Close();
                this.mModalForm = null;
            }
        }
        /// <summary>
        /// 更新注销时间
        /// </summary>
        private void UpdateLogoutTimes()
        {
            if (this.statusStrip.InvokeRequired)
            {
                this.statusStrip.Invoke(new Action(() => { UpdateLogoutTimes(); }));
            }
            else
            {
                if (UserHelper.LoginUser != null && UserHelper.LoginUser.Id > 0)
                {
                    this.toolStripStatusLabelLogoutTimes.Visible = true;
                    int interval = LOGOUT_TIMES - (int)(DateTime.Now.Subtract(this.mLastMouseTime).TotalSeconds + 0.5);
                    interval = interval < 0 ? 0 : interval;
                    this.toolStripStatusLabelLogoutTimes.Text = $"注销倒计时：{interval} 秒";
                }
                else
                {
                    this.toolStripStatusLabelLogoutTimes.Visible = false;
                }
            }
        }
        /// <summary>
        /// 加载菜单图标
        /// </summary>
        private void LoadMenuImages()
        {
            this.toolStripMenuItemSystemStart.Image = CommonLibrary.Resources.Resource.start;
            this.toolStripMenuItemSystemStop.Image = CommonLibrary.Resources.Resource.stop;
            this.toolStripMenuItemSystemOption.Image = CommonLibrary.Resources.Resource.option1;
            this.toolStripMenuItemMESOption.Image = CommonLibrary.Resources.Resource.option1;
            this.toolStripMenuItemSystemExit.Image = CommonLibrary.Resources.Resource.exit;
            this.toolStripMenuItemAlarm.Image = CommonLibrary.Resources.Resource.alarm;
            this.toolStripMenuItemProductQuery.Image = CommonLibrary.Resources.Resource.data1;
            this.toolStripMenuItemUserSwitch.Image = CommonLibrary.Resources.Resource._switch;
            this.toolStripMenuItemUserManage.Image = CommonLibrary.Resources.Resource.user1;
            this.toolStripMenuItemMESLogin.Image = CommonLibrary.Resources.Resource.user1;
            this.toolStripMenuItemDeviceScan.Image = CommonLibrary.Resources.Resource.scan1;
            this.toolStripMenuItemDeviceST5520.Image = CommonLibrary.Resources.Resource.hipot1;
            this.toolStripMenuItemDevice3153.Image = CommonLibrary.Resources.Resource.hipot1;
            this.toolStripMenuItemDevicePLC.Image = CommonLibrary.Resources.Resource.plc;
            this.toolStripMenuItemDeviceHelium.Image = CommonLibrary.Resources.Resource.helium1;
            this.toolStripMenuItemAlarmSetting.Image = CommonLibrary.Resources.Resource.alarm;
        }
        /// <summary>
        /// 主窗体接口
        /// </summary>
        private static FormMain _instance;
        /// <summary>
        /// 主窗体实例
        /// </summary>
        public static FormMain Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new FormMain();
                return _instance;
            }
        }
        /// <summary>
        /// 窗体关闭中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if (DialogResult.Yes == HWMessageBox.ShowYesNo(this, "您确定要退出系统吗?"))
                {
                    PluginManager.UpdateAppIcon -= UpdateLogo;
                    PluginManager.UpdateAppVersion -= UpdateVersion;
#if DEBUG
                    LogHelper.Debug($"【主窗体】 关闭开始：{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
#endif
                    GlobalStatus.APP = EAppStatus.STOP;
                    GlobalStatus.PROGRAM = EAppStatus.STOP;
                    ProductFileManager.Stop();
                    this.mMouseTimer.Stop();
                    this.AppStop();
                    APPInstance.CloseModbuses();
                    AlarmHelper.Close();
                    DeviceClose();
                    APPInstance.PLC.Disconnect();
                    this.mDispatcherTimer.Stop();
                    LogHelper.Debug($"{UserHelper.LoginUser}, 关闭上位机软件");
                    Application.ExitThread();
                    Application.Exit();
                }
                else
                {
                    e.Cancel = true;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        /// <summary>
        /// 设置标题
        /// </summary>
        public void SetTitle()
        {
            string name = AppBasicSetting.Instance().SoftwareName;
            name = string.IsNullOrWhiteSpace(name) ? ProductFileManager.FILE_PREV_NAME : name;
            this.Text = name;
            this.Title = name;
        }
        /// <summary>
        /// 开启启动画面
        /// </summary>
        /// <param name="needOpacity">是否需要透明度</param>
        private void StartSplash(bool needOpacity = true)
        {
            if (needOpacity)
            {
                this.Opacity = 0;
            }
            AppBasicSetting appBasicSetting = AppBasicSetting.Instance();
            SplashHandler.Start(new SofrwareNameLogo()
            {
                SoftwareName = appBasicSetting.SoftwareName,
            });
        }
        /// <summary>
        /// 结束启动画面
        /// </summary>
        /// <param name="needBringToFront">是否窗体前置</param>
        private void EndSplash(bool needBringToFront = true)
        {
            if (FormMain.Instance.InvokeRequired)
            {
                FormMain.Instance.Invoke(new Action(() =>
                {
                    EndSplash(needBringToFront);
                }));
            }
            else
            {
                SplashHandler.Close();
                if (needBringToFront)
                {
                    FormMain.Instance.Opacity = 1;
                    SetForegroundWindow(FormMain.Instance.Handle);
                }
            }
        }
        private void UpdateVersion(string version)
        {
            TSSLabel_Version.Text = $"软件版本：{version}";
        }
        private void UpdateLogo(Bitmap image)
        {
            this.Logo = image;
        }
        /// <summary>
        /// 窗体加载事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_Load(object sender, EventArgs e)
        {
            PluginParam.Instance(true);
            ProductRecordManager.AddProductDataToGrid = (list) =>
            {
                AddDataToGrid(list);
            };
            PluginParam.ShowRunningLog = (isValid, message) =>
            {
                AddRunningViewLog(isValid ? Color.White : Color.Red, message);
            };
            StartSplash();
            this.toolStripMenuItemSystem.BackgroundImage = CommonLibrary.Resources.Resource.MainSysButton1;
            this.toolStripMenuItemProduct.BackgroundImage = CommonLibrary.Resources.Resource.MainSysButton1;
            this.toolStripMenuItemUser.BackgroundImage = CommonLibrary.Resources.Resource.MainSysButton1;
            this.toolStripMenuItemDevice.BackgroundImage = CommonLibrary.Resources.Resource.MainSysButton1;
            this.toolStripMenuItemLocalSetting.BackgroundImage = CommonLibrary.Resources.Resource.MainSysButton1;
            SetTitle();
            OutboundDataGridViewInit();
            SplashHandler.ChangeInfo(">>> 初始化日志控件内容 <<<");
            LogViewInit();
            AddRunningViewLog(ColorSettings.NORMAL_LOG_FORE_COLOR, "正在初始化参数");
            ThreadPool.QueueUserWorkItem(state => LoadUnit());
            IsFormMain = true;
            StartPLCParamtersSaveThread();
        }
        /// <summary>
        /// 初始化连接状态显示
        /// </summary>
        public void InitConnectShowObjs()
        {
            if (tableLayoutPanel.InvokeRequired)
            {
                tableLayoutPanel.Invoke(new UpdateTableLayoutPanel(InitConnectShowObjs));
            }
            else
            {
                this.mShowAndUpdateMutex.WaitOne();
                this.heliumConnectList.Clear();
                this.otherConnectList.Clear();
                Padding mPadding = new Padding(5);
                tableLayoutPanel.Controls.Clear();
                int rowIndex = 0;
                Font labelFont = new Font("微软雅黑", 11);
                Font connectFont = new Font("微软雅黑", 11, FontStyle.Bold);
                plcConnect = APPInstance.IsPLCConnected;
                tableLayoutPanel.Controls.Add(new Label() { Text = "PLC", Font = connectFont, Dock = DockStyle.Fill, ForeColor = Color.White }, 0, 0 + rowIndex);
                tableLayoutPanel.Controls.Add(new Label() { Text = APPInstance.PLC.GetIPPort(), Font = connectFont, AutoSize = true, ForeColor = Color.White }, 1, 0 + rowIndex);
                tableLayoutPanel.Controls.Add(new PictureBox() { Image = plcConnect ? CommonLibrary.Resources.Resource.ball_green_16 : CommonLibrary.Resources.Resource.ball_red_16 }, 2, 0 + rowIndex);
                foreach (var helper in APPInstance.HELPERS)
                {
                    if (helper is HeliumHelper)
                    {
                        var heliumHelper = (HeliumHelper)helper;
                        rowIndex++;
                        tableLayoutPanel.Controls.Add(new Label() { Text = helper.Name, Font = connectFont, Dock = DockStyle.Fill, ForeColor = Color.White }, 0, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = helper.Title, Font = connectFont, Dock = DockStyle.Fill, ForeColor = Color.White }, 1, rowIndex);
                        tableLayoutPanel.Controls.Add(new PictureBox() { Image = heliumHelper.IsConnected ? CommonLibrary.Resources.Resource.ball_green_16 : CommonLibrary.Resources.Resource.ball_red_16 }, 2, rowIndex);
                        heliumConnectList.Add(heliumHelper.IsConnected);
                        rowIndex++;
                        #region                        
                        tableLayoutPanel.Controls.Add(new Label() { Text = "状态", Font = labelFont, ForeColor = Color.White, TextAlign = ContentAlignment.MiddleRight, AutoSize = true, Dock = DockStyle.Fill }, 0, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = heliumHelper.StatusString, Font = connectFont, ForeColor = Color.White, TextAlign = ContentAlignment.MiddleLeft, AutoSize = true, Dock = DockStyle.Fill }, 1, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = "" }, 2, rowIndex);
                        rowIndex++;
                        tableLayoutPanel.Controls.Add(new Label() { Text = "压力(pa)", Font = labelFont, AutoSize = true, ForeColor = Color.White, TextAlign = ContentAlignment.MiddleRight, Dock = DockStyle.Fill }, 0, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = heliumHelper.LeakPressString, Font = connectFont, ForeColor = Color.White, TextAlign = ContentAlignment.MiddleLeft, AutoSize = true, Dock = DockStyle.Fill }, 1, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = "" }, 2, rowIndex);
                        rowIndex++;
                        tableLayoutPanel.Controls.Add(new Label() { Text = "漏率(pa.m³/s)", Font = labelFont, AutoSize = true, ForeColor = Color.White, TextAlign = ContentAlignment.MiddleRight, Dock = DockStyle.Fill }, 0, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = heliumHelper.LeakRateString, Font = connectFont, ForeColor = Color.White, TextAlign = ContentAlignment.MiddleLeft, AutoSize = true, Dock = DockStyle.Fill }, 1, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = "" }, 2, rowIndex);
                        #endregion
                    }
                    else
                    {
                        rowIndex++;
                        tableLayoutPanel.Controls.Add(new Label() { Text = helper.Name, Font = connectFont, Dock = DockStyle.Fill, ForeColor = Color.White }, 0, rowIndex);
                        tableLayoutPanel.Controls.Add(new Label() { Text = helper.Title, Font = connectFont, Dock = DockStyle.Fill, AutoSize = true, ForeColor = Color.White }, 1, rowIndex);
                        tableLayoutPanel.Controls.Add(new PictureBox() { Image = helper.IsConnected ? CommonLibrary.Resources.Resource.ball_green_16 : CommonLibrary.Resources.Resource.ball_red_16 }, 2, rowIndex);
                        this.otherConnectList.Add(helper.IsConnected);
                    }
                }
                UpdateLabelMES();
                this.mShowAndUpdateMutex.ReleaseMutex();
                Application.DoEvents();
            }
        }
        private void UpdateLabelMES()
        {
            var online = MesHelper.IsMesOnline;
            this.toolStripStatusLabelMES.Text = online && !string.IsNullOrWhiteSpace(MesCommonHelper.MES_USERNAME) ? 
                $"[{MesCommonHelper.MES_USERNAME}] MES在线模式" : "MES离线模式";
        }

        /// <summary>
        /// 报警开始，看需不需要上传，不需要可以啥都不写
        /// </summary>
        /// <param name="code">报警代码</param>
        /// <param name="name">报警内容</param>
        /// <param name="startTime">报警时间</param>
        private void UploadStartAlarm(string code, string name, DateTime startTime)
        {
            try
            {
                var param = new MESAlarmExcuteEntity()
                {
                    AlarmCode = code,
                    AlarmContent = name,
                    StartTime = startTime.ToString("yyyy-MM-dd HH:mm:ss")
                };
                PluginManager.Instance.Excute("MES", "MES_START_ALARM", CommonHelper.GetJsonString(param, Formatting.None));
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
            AddAlarmViewLog(Color.Red, $"【报警】报警代码：{code}，报警内容：{name}，报警时间：{startTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
        }
        /// <summary>
        /// 报警结束，看需不需要上传，不需要可以啥都不写
        /// </summary>
        /// <param name="code">报警代码</param>
        /// <param name="name">报警内容</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        private void UploadEndAlarm(string code, string name, DateTime startTime, DateTime endTime)
        {
        }
        /// <summary>
        /// 窗体加载后，尝试初始化各个对象
        /// </summary>
        private void LoadUnit()
        {
            SplashHandler.ChangeInfo(">>> 加载今日数据 <<<");
            //加载生产记录数据显示控件lsw
            ProductRecordManager.Instance.Init();
            AddRunningViewLog(ColorSettings.NORMAL_LOG_FORE_COLOR, "设备初始化");
            SplashHandler.ChangeInfo(">>> 设备初始化 <<<");
            this.menuStrip.Enabled = false;
            this.buttonStart.Enabled = false;
            DeviceInit();
            APPInstance.StartModbuses();
            AddRunningViewLog(ColorSettings.NORMAL_LOG_FORE_COLOR, "出站处理初始化");
            SplashHandler.ChangeInfo(">>> 出站处理初始化 <<<");
            CleanManager.Instance.Init();
            AddRunningViewLog(ColorSettings.NORMAL_LOG_FORE_COLOR, "报警信息处理初始化");
            SplashHandler.ChangeInfo(">>> 报警信息处理初始化 <<<");
            //报警
            AlarmHelper.Init((code, name, startTime, endTime) =>
            {
                UploadEndAlarm(code, name, startTime, endTime);
            }, (code, name, startTime) =>
            {
                UploadStartAlarm(code, name, startTime);
            });
            this.menuStrip.Enabled = true;
            this.buttonStart.Enabled = true;
            isFormMainLoadUnit = true;
            AddRunningViewLog(ColorSettings.NORMAL_LOG_FORE_COLOR, "初始化参数完成");
            Thread thread = new Thread(() =>
            {
                while (GlobalStatus.PROGRAM == EAppStatus.RUN)
                {
                    UpdateFormMainUI();
                    Thread.Sleep(500);
                }
            });
            thread.IsBackground = true;
            thread.Start();
            #region 心跳
            Thread heartbeatThead = new Thread(() =>
            {
                while (GlobalStatus.PROGRAM == EAppStatus.RUN)
                {
                    Task.Run(async () =>
                    {
#if DEBUG
                        LogHelper.Debug($"【心跳】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
#endif
                        await PluginManager.Instance.ExcuteAsync(PluginParam.Instance().GetPluginParam("App", "HEARTBEAT_PLC"));
                    });
                    Thread.Sleep(1000);
                }
            });
            heartbeatThead.IsBackground = true;
            heartbeatThead.Start();
            #endregion
            ProductFileManager.Start();//开启出站文件保存
            if (threadAuto == null || threadAuto.ThreadState == System.Threading.ThreadState.Stopped)
            {
                threadAuto = new Thread(() =>
                {
                    Auto();
                });
                threadAuto.Start();
            }
            if (BusinessConfig.Instance().IsAutoStart)
            {
                this.MenuItemSystemStart_Click(null, null);
            }
            SplashHandler.ChangeInfo(">>> 初始化完成 <<<");
            EndSplash();
        }
        #region 主线程Auto,设备状态，报警，离线缓存数据上传，心跳频率，实时数据显示
        /// <summary>
        /// 主线程Auto,设备状态，报警，离线缓存数据上传，心跳频率，实时数据显示
        /// </summary>
        private void Auto()
        {
            mAppParam = AppPLCSetting.Instance(true);
            EPLCState lastPLCState = EPLCState.Idle;
            while (GlobalStatus.PROGRAM == EAppStatus.RUN)
            {
                //设备状态监控
                //10手动 20初始化状态 30复位中 40复位完成 运行中间状态 60自动运行中 70设备停止中 80设备故障报警;
                //1：正常运行，2：停机，3：故障;
                EPLCState deviceStatus = CommonHelper.GetEnumByRealValue(APPInstance.PLC.ReadShort(mAppParam.EQMStatus), EPLCState.Idle);
                if (deviceStatus != lastPLCState)//状态变化，立即上传
                {
                    LogHelper.Warn($"设备状态变更：{lastPLCState} ==> {deviceStatus}");
                    var status = CommonHelper.GetEnumDescription(deviceStatus);
                    this.labelStatus.Text = status;
                    this.pic_Runing.Image = CommonLibrary.Resources.Resource.ball_yellow;
                    this.labelStatus.ForeColor = Color.Gold;
                    LogHelper.Debug($"{UserHelper.LoginUser}, {status}");
                    switch (deviceStatus)
                    {
                        case EPLCState.Shutdown:
                        case EPLCState.Turnover:
                        case EPLCState.Stoping:
                        case EPLCState.Alarm:
                            this.pic_Runing.Image = CommonLibrary.Resources.Resource.ball_red;
                            break;
                        case EPLCState.Idle:
                        case EPLCState.Normal:
                        case EPLCState.AutoRunning:
                        case EPLCState.Reseted:
                            this.pic_Runing.Image = CommonLibrary.Resources.Resource.ball_green;
                            this.labelStatus.ForeColor = Color.YellowGreen;
                            break;
                    }
                    lastPLCState = deviceStatus;
                    try
                    {
                        var param = new MESStatusExcuteEntity()
                        {
                            Status = deviceStatus
                        };
                        PluginManager.Instance.Excute("MES", "MES_DEVICE_STATUS", CommonHelper.GetJsonString(param, Formatting.None));
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                }
                Thread.Sleep(500);
            }
        }
        #endregion
        #region 实时更新UI界面信息
        /// <summary>
        /// 实时更新UI界面事件代理
        /// </summary>
        public delegate void UpdateTableLayoutPanel();
        /// <summary>
        /// 实时更新界面信息
        /// </summary>
        private void UpdateFormMainUI()
        {
            if (GlobalStatus.PROGRAM == EAppStatus.RUN && this.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    UpdateFormMainUI();
                }));
            }
            else
            {
                if (GlobalStatus.PROGRAM == EAppStatus.RUN)
                {
                    if (!isFormMainLoadUnit)
                        return;
                    this.mShowAndUpdateMutex.WaitOne();

                    this.labelInboundNum.Text = this.mProductData.InboundNum.ToString();
                    this.labelOutboundNum.Text = this.mProductData.OutboundNum.ToString();
                    this.labelScanNGNum.Text = this.mProductData.ScanNGNum.ToString();
                    Label label1 = tableLayoutPanel.Controls[1] as Label;
                    if (!label1.Text.Equals(APPInstance.PLC.GetIPPort()))
                    {
                        label1.Text = APPInstance.PLC.GetIPPort();
                    }
                    if (this.plcConnect != APPInstance.IsPLCConnected)
                    {
                        this.plcConnect = APPInstance.IsPLCConnected;
                        PictureBox picture = tableLayoutPanel.Controls[2] as PictureBox;
                        picture.Image = this.plcConnect ? CommonLibrary.Resources.Resource.ball_green_16 : CommonLibrary.Resources.Resource.ball_red_16;
                    }
                    int total = 2;
                    int heliumIndex = 0;
                    int otherIndex = 0;
                    foreach (var helper in APPInstance.HELPERS)
                    {
                        try
                        {
                            Label label = tableLayoutPanel.Controls[2 + total] as Label;
                            if (!label.Text.Equals(helper.Title))
                            {
                                label.Text = helper.Title;
                            }
                            if (helper is HeliumHelper)
                            {
                                if (heliumConnectList[heliumIndex] != helper.IsConnected)
                                {
                                    PictureBox picture = tableLayoutPanel.Controls[3 + total] as PictureBox;
                                    if (picture != null)
                                    {
                                        picture.Image = helper.IsConnected ? CommonLibrary.Resources.Resource.ball_green_16 : CommonLibrary.Resources.Resource.ball_red_16;
                                    }
                                }
                                heliumConnectList[heliumIndex++] = helper.IsConnected;
                                //状态
                                Label labelStatus = tableLayoutPanel.Controls[3 + total + 2] as Label;
                                Label labelPress = tableLayoutPanel.Controls[3 + total + 5] as Label;
                                Label labelRate = tableLayoutPanel.Controls[3 + total + 8] as Label;

                                HeliumHelper heliumHelper = helper as HeliumHelper;
                                labelStatus.Text = heliumHelper.StatusString;
                                labelPress.Text = heliumHelper.LeakPressString;
                                labelRate.Text = heliumHelper.LeakRateString;
                                //压力
                                //漏率
                                total += 12;
                            }
                            else
                            {
                                if (otherConnectList[otherIndex] != helper.IsConnected)
                                {
                                    PictureBox picture = tableLayoutPanel.Controls[3 + total] as PictureBox;
                                    picture.Image = helper.IsConnected ? CommonLibrary.Resources.Resource.ball_green_16 : CommonLibrary.Resources.Resource.ball_red_16;
                                }
                                otherConnectList[otherIndex++] = helper.IsConnected;
                                total += 3;
                            }
                        }
                        catch (Exception ex)
                        {
                            LogHelper.Error(ex);
                            break;
                        }
                    }
                    this.mShowAndUpdateMutex.ReleaseMutex();
                }
            }
        }
        #endregion
        #region 运行日志，Mes日志内容
        /// <summary>
        /// Mes日志
        /// </summary>
        /// <param name="foreColor">字体颜色</param>
        /// <param name="content">内容</param>
        public void AddMESViewLog(Color foreColor, string content)
        {
            AddViewLog(this.dataGridViewMESLog, foreColor, new string[] { "dcMESContent", content });
            LogHelper.Mes(content);
        }
        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="foreColor">字体颜色</param>
        /// <param name="content">内容</param>
        public void AddErrorViewLog(Color foreColor, string content)
        {
            AddViewLog(this.dataGridViewErrorLog, foreColor, new string[] { "dcErrorContent", content });
            LogHelper.Error(null, "", content);
        }
        /// <summary>
        /// 报警日志
        /// </summary>
        /// <param name="foreColor">字体颜色</param>
        /// <param name="content">内容</param>
        public void AddAlarmViewLog(Color foreColor, string content)
        {
            AddViewLog(this.dataGridViewAlarmLog, foreColor, new string[] { "dcAlarmContent", content });
            LogHelper.Error(null, "", content);
        }
        /// <summary>
        /// 运行日志
        /// </summary>
        /// <param name="foreColor">字体颜色</param>
        /// <param name="content">内容</param>
        public void AddRunningViewLog(Color foreColor, string content)
        {
            AddViewLog(this.dataGridViewRunningLog, foreColor, new string[] { "dcRunningContent", content });
            LogHelper.Info(content);
        }
        /// <summary>
        /// 增加日志
        /// </summary>
        /// <param name="dataGridView">DataGridView控件</param>
        /// <param name="foreColor">字体颜色</param>
        /// <param name="nameValues">对应的列与值</param>
        private void AddViewLog(DataGridView dataGridView, Color foreColor, params string[] nameValues)
        {
            try
            {
                if (dataGridView.InvokeRequired)
                {
                    dataGridView.Invoke(new Action(() =>
                    {
                        AddViewLog(dataGridView, foreColor, nameValues);
                    }));
                }
                else
                {
                    if (GlobalStatus.PROGRAM == EAppStatus.RUN)
                    {
                        if (dataGridView.Rows != null && dataGridView.Rows.Count > 1000)
                        {
                            dataGridView.Rows.Clear();
                        }
                        if (dataGridView.Columns != null && dataGridView.Columns.Count > 0)
                        {
                            var index = dataGridView.Rows.Add(1);
                            var row = dataGridView.Rows[index];
                            row.Cells[0].Value = (index + 1).ToString();
                            row.Cells[0].Style.ForeColor = foreColor;
                            row.Cells[0].Style.SelectionForeColor = row.Cells[0].Style.ForeColor;
                            row.Cells[1].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                            row.Cells[1].Style.ForeColor = foreColor;
                            row.Cells[1].Style.SelectionForeColor = row.Cells[1].Style.ForeColor;
                            if (nameValues != null && nameValues.Length > 0 && nameValues.Length % 2 == 0)
                            {
                                for (var i = 0; i < nameValues.Length / 2; i++)
                                {
                                    row.Cells[nameValues[i * 2]].Value = nameValues[i * 2 + 1];
                                    row.Cells[nameValues[i * 2]].Style.ForeColor = foreColor;
                                    row.Cells[nameValues[i * 2]].Style.SelectionForeColor = foreColor;
                                }
                            }
                            if (dataGridView.Rows.Count > 0)
                            {
                                dataGridView.ClearSelection();
                                dataGridView.Rows[dataGridView.Rows.Count - 1].Selected = true;
                                dataGridView.FirstDisplayedScrollingRowIndex = dataGridView.Rows.Count - 1;
                            }
                        }
                        Application.DoEvents();
                    }
                }
            }
            catch
            { }
            Application.DoEvents();
        }
        /// <summary>
        /// 初始化各日志控件
        /// </summary>
        private void LogViewInit()
        {
            var dcRunningId = new DataGridViewTextBoxColumn()
            {
                Name = "dcRunningId",
                HeaderText = "序号",
                ReadOnly = true,
                Width = 80
            };
            var dcRunningTime = new DataGridViewTextBoxColumn()
            {
                Name = "dcRunningTime",
                HeaderText = "时间",
                ReadOnly = true,
                Width = 220
            };
            var dcRunningContent = new DataGridViewTextBoxColumn()
            {
                Name = "dcRunningContent",
                HeaderText = "内容",
                ReadOnly = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
            };
            this.dataGridViewRunningLog.Columns.Add(dcRunningId);
            this.dataGridViewRunningLog.Columns.Add(dcRunningTime);
            this.dataGridViewRunningLog.Columns.Add(dcRunningContent);
            this.dataGridViewRunningLog.DoubleBufferedDataGirdView(true);
            this.dataGridViewRunningLog.InitStyle();

            var dcErrorId = new DataGridViewTextBoxColumn()
            {
                Name = "dcErrorId",
                HeaderText = "序号",
                ReadOnly = true,
                Width = 80
            };
            var dcErrorTime = new DataGridViewTextBoxColumn()
            {
                Name = "dcErrorTime",
                HeaderText = "时间",
                ReadOnly = true,
                Width = 220
            };
            var dcErrorContent = new DataGridViewTextBoxColumn()
            {
                Name = "dcErrorContent",
                HeaderText = "内容",
                ReadOnly = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
            };
            this.dataGridViewErrorLog.Columns.Add(dcErrorId);
            this.dataGridViewErrorLog.Columns.Add(dcErrorTime);
            this.dataGridViewErrorLog.Columns.Add(dcErrorContent);
            this.dataGridViewErrorLog.DoubleBufferedDataGirdView(true);
            this.dataGridViewErrorLog.InitStyle();


            var dcAlarmId = new DataGridViewTextBoxColumn()
            {
                Name = "dcAlarmId",
                HeaderText = "序号",
                ReadOnly = true,
                Width = 80
            };
            var dcAlarmTime = new DataGridViewTextBoxColumn()
            {
                Name = "dcAlarmTime",
                HeaderText = "时间",
                ReadOnly = true,
                Width = 220
            };
            var dcAlarmContent = new DataGridViewTextBoxColumn()
            {
                Name = "dcAlarmContent",
                HeaderText = "内容",
                ReadOnly = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
            };
            this.dataGridViewAlarmLog.Columns.Add(dcAlarmId);
            this.dataGridViewAlarmLog.Columns.Add(dcAlarmTime);
            this.dataGridViewAlarmLog.Columns.Add(dcAlarmContent);
            this.dataGridViewAlarmLog.DoubleBufferedDataGirdView(true);
            this.dataGridViewAlarmLog.InitStyle();


            var dcMESId = new DataGridViewTextBoxColumn()
            {
                Name = "dcMESId",
                HeaderText = "序号",
                ReadOnly = true,
                Width = 80
            };
            var dcMESTime = new DataGridViewTextBoxColumn()
            {
                Name = "dcMESTime",
                HeaderText = "时间",
                ReadOnly = true,
                Width = 220
            };
            var dcMESContent = new DataGridViewTextBoxColumn()
            {
                Name = "dcMESContent",
                HeaderText = "内容",
                ReadOnly = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
            };
            this.dataGridViewMESLog.Columns.Add(dcMESId);
            this.dataGridViewMESLog.Columns.Add(dcMESTime);
            this.dataGridViewMESLog.Columns.Add(dcMESContent);
            this.dataGridViewMESLog.DoubleBufferedDataGirdView(true);
            this.dataGridViewMESLog.InitStyle();
        }
        #endregion 运行日志，Mes日志内容
        #region 软件运行时钟
        /// <summary>
        /// 程序开始时间
        /// </summary>
        private DateTime appStartTime = DateTime.Now;
        /// <summary>
        /// 时间计时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            DateTime now = DateTime.Now;
            TimeSpan timeSpan = now.Subtract(appStartTime);
            TSSLabel_LocalTime.Text = $"当前时间：{now.ToString("yyyy-MM-dd HH:mm:ss")}";
            TSSLabel_RunTime.Text = $"运行时间：{(timeSpan.Days > 0 ? (timeSpan.Days * 24 + timeSpan.Hours).ToString() : timeSpan.ToString(@"hh"))}{timeSpan.ToString(@"\:mm\:ss")}";
        }
        #endregion  
        Thread threadAuto;
        /// <summary>
        /// 启动按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SofttoolStripButton_Click(object sender, EventArgs e)
        {
            CheckPermissionAction(1, new Action(() =>
            {
                if (GlobalStatus.APP == EAppStatus.RUN)
                {
                    this.MenuItemSystemStop_Click(null, null);
                }
                else
                {
                    this.MenuItemSystemStart_Click(null, null);
                }
            }));
        }
        /// <summary>
        /// 清零
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void linkLabelClearNums_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (UserHelper.CheckPermission(this, 2))
            {
                if (DialogResult.Yes == HWMessageBox.ShowYesNo(this, "您确定要产量清零?"))
                {
                    Task.Run(async () =>
                    {
                        await PluginManager.Instance.ExcuteAsync(PluginParam.Instance().GetPluginParam("App", "ZERO_PLC"));
                    });
                    LogHelper.Debug($"{UserHelper.LoginUser}, 产量计数面板清零");
                    HWMessageBox.Show(this, "清零成功");
                }
            }
        }
        #region 仪器初始化
        /// <summary>
        /// 停止所有设备
        /// </summary>
        private void DeviceStop()
        {
            APPInstance.StopHelpers();
        }
        /// <summary>
        /// 启动所有设备
        /// </summary>
        private void DeviceStart()
        {
            APPInstance.StartHelpers();
        }
        /// <summary>
        /// 互斥量
        /// </summary>
        private Mutex mutex = new Mutex(false);
        /// <summary>
        /// 设备退出
        /// </summary>
        private void DeviceClose()
        {
            mutex.WaitOne();
            APPInstance.DisconnectHelpers();
            mutex.ReleaseMutex();
        }
        /// <summary>
        /// 设备初始化
        /// </summary>
        private void DeviceInit()
        {
            mutex.WaitOne();
            SplashHandler.ChangeInfo(">>> PLC初始化 <<<");
            APPInstance.ResetPLC();
            SplashHandler.ChangeInfo(">>> 各类设备初始化 <<<");
            APPInstance.ResetHelpers();
            APPInstance.ResetModbuses();
            SplashHandler.ChangeInfo(">>> 设备状态初始化 <<<");
            InitConnectShowObjs();
            mutex.ReleaseMutex();
        }
        private void SetAppStatusText()
        {
            if (this.labelAppStatus.InvokeRequired)
            {
                this.labelAppStatus.Invoke(new Action(() => { SetAppStatusText(); }));
            }
            else
            {
                this.labelAppStatus.Text = GlobalStatus.APP == EAppStatus.RUN ? string.Empty : "上位机未启动";
            }
        }
        #endregion
        /// <summary>
        /// 启动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemSystemStart_Click(object sender, EventArgs e)
        {
            if (!APPInstance.IsPLCConnected)
            {
                HWMessageBox.Show(this, "PLC未连接，不允许启动");
                return;
            }
            if (GlobalStatus.APP == EAppStatus.RUN)
                return;

            bool isContinous = false;

            if (!MesHelper.IsMesOnline)
            {
                //this.toolStripStatusLabelMES.Text = "MES离线模式";
                if (HWMessageBox.ShowYesNo(this, "MES暂不可用，是否启用上位机？") == DialogResult.Yes)
                {
                    MesCommonHelper.MES_USERNAME = string.Empty;
                    isContinous = true;
                }
            }
            else
            {
                //this.toolStripStatusLabelMES.Text = string.IsNullOrWhiteSpace(MesCommonHelper.MES_USERNAME) ? "MES在线未登录模式" : "MES在线模式";
                DialogResult dialogResult = ShowPluginForm("App", "MES_FORM_LOGIN");
                isContinous = dialogResult == DialogResult.OK;
                if (dialogResult != DialogResult.OK)
                {
                    if (HWMessageBox.ShowYesNo(this, "MES登录失败，是否启用离线模式？") == DialogResult.Yes)
                    {
                        MesCommonHelper.MES_USERNAME = string.Empty;
                        //this.toolStripStatusLabelMES.Text = "MES离线模式";
                        isContinous = true;
                    }
                }
                else
                {
                    //this.toolStripStatusLabelMES.Text = "MES在线模式";
                    isContinous = true;
                }
            }
            UpdateLabelMES();

            if (isContinous)
            {
                GlobalStatus.APP = EAppStatus.RUN;
                BaseHelper.StartReadTriggers();
                DeviceStart();
                CleanManager.Instance.StartThread();//开启出站数据采集流程
                this.buttonStart.Text = $"{FontHelper.STOP} 停止";
                this.buttonStart.ForeColor = Color.Red;
                SetAppStatusText();
                LogHelper.Debug($"{UserHelper.LoginUser} 上位机启动");
            }
        }
        /// <summary>
        /// 停止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemSystemStop_Click(object sender, EventArgs e)
        {
            if (GlobalStatus.APP == EAppStatus.RUN)
            {
                AppStop();
            }
        }
        private void AppStop()
        {
            GlobalStatus.APP = EAppStatus.STOP;
            DeviceStop();
            CleanManager.Instance.StopThread();
            this.buttonStart.Text = $"{FontHelper.START} 启动";
            this.buttonStart.ForeColor = Color.Green;
            SetAppStatusText();
            LogHelper.Debug($"{UserHelper.LoginUser}, 停止软件");
        }
        /// <summary>
        /// 选项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemSystemOption_Click(object sender, EventArgs e)
        {
            CheckPermissionAction(1, new Action(() =>
            {
                var dialogResult = ShowPluginForm("App", "OTHERS_BASIC_OPTIONS");
                if (dialogResult == DialogResult.OK)
                {
                    SetTitle();
                    UpdateLabelMES();
                }
            }));
        }

        private void MenuItemMESOption_Click(object sender, EventArgs e)
        {
            CheckPermissionAction(1, new Action(() =>
            {
                ShowPluginForm("App", "MES_FORM");
            }));
        }
        /// <summary>
        /// 退出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemSystemExit_Click(object sender, EventArgs e)
        {
            Close();
        }
        /// <summary>
        /// 数据查询
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemProductQuery_Click(object sender, EventArgs e)
        {
            ShowChildForm(new FormRecordQuery(), false);
        }
        /// <summary>
        /// 用户切换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemUserSwitch_Click(object sender, EventArgs e)
        {
            ShowChildForm(new FormLogin(), false);
        }
        /// <summary>
        /// 用户管理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemUserManage_Click(object sender, EventArgs e)
        {
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormUser());
            }));
        }
        /// <summary>
        /// MES 用户登录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripMenuItemMESLogin_Click(object sender, EventArgs e)
        {
            ShowPluginForm("App", "MES_FORM_LOGIN");
            UpdateLabelMES();
        }
        /// <summary>
        /// PLC配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemDevicePLC_Click(object sender, EventArgs e)
        {
            var dialogResult = DialogResult.None;
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormPLC());
            }));
            if (dialogResult == DialogResult.OK)
            {
                this.InitConnectShowObjs();
            }
        }
        /// <summary>
        /// 氦检仪配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemDeviceHelium_Click(object sender, EventArgs e)
        {
            var dialogResult = DialogResult.None;
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormHelium());
            }));
            if (dialogResult == DialogResult.OK)
            {
                this.InitConnectShowObjs();
            }
        }
        /// <summary>
        /// 扫码枪配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemDeviceScan_Click(object sender, EventArgs e)
        {
            var dialogResult = DialogResult.None;
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormMultiScan());
            }));
            if (dialogResult == DialogResult.OK)
            {
                this.InitConnectShowObjs();
            }
        }
        /// <summary>
        /// ST5520配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemDeviceST5520_Click(object sender, EventArgs e)
        {
            var dialogResult = DialogResult.None;
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormHIOKIST5520());
            }));
            if (dialogResult == DialogResult.OK)
            {
                this.InitConnectShowObjs();
            }
        }
        /// <summary>
        /// 3153配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItemDevice3153_Click(object sender, EventArgs e)
        {
            var dialogResult = DialogResult.None;
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormHIOKI3153());
            }));
            if (dialogResult == DialogResult.OK)
            {
                this.InitConnectShowObjs();
            }
        }
        /// <summary>
        /// 短路测试仪配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripMenuItemDeviceHipot_Click(object sender, EventArgs e)
        {
            var dialogResult = DialogResult.None;
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormRJ6902());
            }));
            if (dialogResult == DialogResult.OK)
            {
                this.InitConnectShowObjs();
            }
        }
        /// <summary>
        /// 鼠标进入事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonProgram_MouseEnter(object sender, EventArgs e)
        {
            ((Button)sender).Font = new Font(((Button)sender).Font.FontFamily, 22, FontStyle.Bold);
        }
        /// <summary>
        /// 鼠标离开事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonProgram_MouseLeave(object sender, EventArgs e)
        {
            ((Button)sender).Font = new Font(((Button)sender).Font.FontFamily, 18, FontStyle.Bold);
        }
        /// <summary>
        /// 数据控件初始化
        /// </summary>
        public void OutboundDataGridViewInit()
        {
            CommonHelper.InitDataGridViewColumns<ProductInfo>(this.dataGridViewProduct, new string[] { "Id", "BarCode" });
        }
        /// <summary>
        /// 数据显示到控件的代理
        /// </summary>
        /// <param name="productInfos"></param>
        public delegate void AddDataToGridDelegate(List<ProductInfo> productInfos);
        /// <summary>
        /// 数据显示到控件中
        /// </summary>
        /// <param name="productInfos"></param>
        public void AddDataToGrid(List<ProductInfo> productInfos)
        {
            if (this.dataGridViewProduct.InvokeRequired)
            {
                this.dataGridViewProduct.Invoke(new AddDataToGridDelegate(AddDataToGrid), productInfos);
            }
            else
            {
                if (this.dataGridViewProduct.Rows.Count > 3000)
                {
                    this.dataGridViewProduct.Rows.Clear();
                }
                ProductInfo productInfo = new ProductInfo();
                System.Reflection.PropertyInfo[] properties = productInfo.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
                int count = this.dataGridViewProduct.Rows.Count;
                foreach (var p in productInfos)
                {
                    count += 1;
                    var row = this.dataGridViewProduct.Rows[this.dataGridViewProduct.Rows.Add(1)];
                    row.Cells[0].Value = count;
                    row.Cells[0].Style.ForeColor = p.GetForeColor("Id");
                    row.Cells[0].Style.SelectionForeColor = row.Cells[0].Style.ForeColor;
                    for (var i = 1; i < this.dataGridViewProduct.Columns.Count; i++)
                    {
                        var column = this.dataGridViewProduct.Columns[i];
                        var pInfo = properties.Where(v => v.Name == column.Name).FirstOrDefault();
                        if (pInfo != null)
                        {
                            object objValue = pInfo.GetValue(p);
                            string strValue = objValue == null || string.IsNullOrWhiteSpace(objValue.ToString()) ? "-" : objValue.ToString();
                            row.Cells[i].Value = strValue;
                            row.Cells[i].Style.ForeColor = p.GetForeColor(pInfo.Name);
                            row.Cells[i].Style.SelectionForeColor = row.Cells[i].Style.ForeColor;
                        }
                        else
                        {
                            row.Cells[i].Value = "-";
                        }
                    }
                    row.Tag = p;
                }
                if (this.dataGridViewProduct.Rows.Count > 0)
                {
                    this.dataGridViewProduct.ClearSelection();
                    this.dataGridViewProduct.Rows[this.dataGridViewProduct.Rows.Count - 1].Selected = true;
                    this.dataGridViewProduct.FirstDisplayedScrollingRowIndex = this.dataGridViewProduct.Rows.Count - 1;
                }
                Application.DoEvents();
            }
        }
        private void MenuItemExportTimeLine_Click(object sender, EventArgs e)
        {
            try
            {
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = "*.xlsx|*.xlsx";
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    bool result = TimeLineHelper.ExportToExcel(dialog.FileName);
                    if (result)
                    {
                        HWMessageBox.Show(this, "导出成功");
                        CommonHelper.OpenExcelFile(dialog.FileName);
                    }
                    else
                    {
                        HWMessageBox.Show(this, "导出失败");
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                HWMessageBox.Show(this, $"发生异常：{ex.Message}", "异常");
            }
        }
        private void toolStripMenuItemAlarm_Click(object sender, EventArgs e)
        {
            ShowChildForm(new FormAlarmQuery(), false);
        }
        private void toolStripMenuItemAlarmSetting_Click(object sender, EventArgs e)
        {
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormAlarm());
            }));
        }
        private void toolStripMenuItemTimeLineSetting_Click(object sender, EventArgs e)
        {
            CheckPermissionAction(1, new Action(() =>
            {
                ShowChildForm(new FormTimeLine());
            }));
        }
        private void FormMain_Shown(object sender, EventArgs e)
        {
        }
        private void MenuItemSystemMouseEnter(object sender, EventArgs e)
        {
            var menu = sender as ToolStripMenuItem;
            if (menu != null)
            {
                menu.ForeColor = Color.Black;
            }
        }
        private void MenuItemSystemMouseLeave(object sender, EventArgs e)
        {
            var menu = sender as ToolStripMenuItem;
            if (menu != null && !menu.DropDown.Visible)
            {
                menu.ForeColor = Color.White;
            }
        }
        private void MenuItemSystemDropDownOpened(object sender, EventArgs e)
        {
            var menu = sender as ToolStripMenuItem;
            if (menu != null)
            {
                menu.ForeColor = Color.Black;
            }
        }
        private void MenuItemSystemDropDownClosed(object sender, EventArgs e)
        {
            var menu = sender as ToolStripMenuItem;
            if (menu != null)
            {
                menu.ForeColor = Color.White;
            }
        }
        private DialogResult ShowPluginForm(string tag, string identity, string paramString = "")
        {
            DialogResult dialogResult = DialogResult.Cancel;
            var form = PluginManager.Instance.GetForm(tag, identity, paramString = "");
            if (form != null)
            {
                dialogResult = ShowChildForm(form);
            }
            else
            {
                HWMessageBox.Show(this, "暂不提供此功能");
            }
            return dialogResult;
        }
        /// <summary>
        /// 初始化各类饼图
        /// </summary>
        private void InitPercentChart()
        {
            InitHeliumPercentChart();
            InitHIOKI3153PercentChart();
            InitHIOKIST5520PercentChart();
            new Thread(() => { ShowPercentChart(); }) { IsBackground = true }.Start();
        }
        /// <summary>
        /// 显示各类饼图
        /// </summary>
        private void ShowPercentChart()
        {
            while (GlobalStatus.PROGRAM == EAppStatus.RUN)
            {
                try
                {
                    lock (this.LOCK_READ_PRODUCT_DATA)
                    {
                        ShowHeliumPercent();
                        ShowHIOKI3153Percent();
                        ShowHIOKIST5520Percent();
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                Thread.Sleep(1000);
            }
        }
        /// <summary>
        /// 初始化氦检数量统计饼图
        /// </summary>
        private void InitHeliumPercentChart()
        {
            this.chartHeliumPercent.DoubleBufferredChart(true);
            this.chartHeliumPercent.Series[0].Points.Clear();
            this.chartHeliumPercent.Series[0].Points.Add(new System.Windows.Forms.DataVisualization.Charting.DataPoint(0, 0));
            this.chartHeliumPercent.Series[0].Points[0].LegendText = "OK";
            this.chartHeliumPercent.Series[0].Points[0].Color = Color.Green;
            this.chartHeliumPercent.Series[0].Points[0].LabelForeColor = Color.White;
            this.chartHeliumPercent.Series[0].Points.Add(new System.Windows.Forms.DataVisualization.Charting.DataPoint(1, 0));
            this.chartHeliumPercent.Series[0].Points[1].LegendText = "NG";
            this.chartHeliumPercent.Series[0].Points[1].Color = Color.Red;
            this.chartHeliumPercent.Series[0].Points[1].LabelForeColor = Color.White;
            this.chartHeliumPercent.Series[0].CustomProperties = "PieLabelStyle = Outside";
            this.chartHeliumPercent.Series[0]["PieLineColor"] = "White";
        }
        /// <summary>
        /// 显示氦检测试数量
        /// </summary>
        private void ShowHeliumPercent()
        {
            if (this.chartHeliumPercent.InvokeRequired)
            {
                this.chartHeliumPercent.Invoke(new Action(() => { ShowHeliumPercent(); }));
            }
            else
            {
                var ngNum = this.mProductData.HeliumNGNum;
                var totalNum = this.mProductData.HeliumNum;
                this.chartHeliumPercent.Series[0].Points[0].SetValueY(totalNum - ngNum);
                this.chartHeliumPercent.Series[0].Points[0].LegendText = $"OK：{totalNum - ngNum}";
                this.chartHeliumPercent.Series[0].Points[1].SetValueY(ngNum);
                this.chartHeliumPercent.Series[0].Points[1].LegendText = $"NG：{ngNum}";
            }
        }
        /// <summary>
        /// 初始化绝缘测试数量统计饼图
        /// </summary>
        private void InitHIOKIST5520PercentChart()
        {
            this.chartHIOKIST5520Percent.DoubleBufferredChart(true);
            this.chartHIOKIST5520Percent.Series[0].Points.Clear();
            this.chartHIOKIST5520Percent.Series[0].Points.Add(new System.Windows.Forms.DataVisualization.Charting.DataPoint(0, 0));
            this.chartHIOKIST5520Percent.Series[0].Points[0].LegendText = "OK";
            this.chartHIOKIST5520Percent.Series[0].Points[0].Color = Color.Green;
            this.chartHIOKIST5520Percent.Series[0].Points[0].LabelForeColor = Color.White;
            this.chartHIOKIST5520Percent.Series[0].Points.Add(new System.Windows.Forms.DataVisualization.Charting.DataPoint(1, 0));
            this.chartHIOKIST5520Percent.Series[0].Points[1].LegendText = "NG";
            this.chartHIOKIST5520Percent.Series[0].Points[1].Color = Color.Red;
            this.chartHIOKIST5520Percent.Series[0].Points[1].LabelForeColor = Color.White;
            this.chartHIOKIST5520Percent.Series[0].CustomProperties = "PieLabelStyle = Outside";
            this.chartHIOKIST5520Percent.Series[0]["PieLineColor"] = "White";
        }
        /// <summary>
        /// 显示绝缘测试数量
        /// </summary>
        private void ShowHIOKIST5520Percent()
        {
            if (this.chartHIOKIST5520Percent.InvokeRequired)
            {
                this.chartHIOKIST5520Percent.Invoke(new Action(() => { ShowHIOKIST5520Percent(); }));
            }
            else
            {
                var ngNum = this.mProductData.InsulationTestNGNum;
                var totalNum = this.mProductData.InsulationTestNum;
                this.chartHIOKIST5520Percent.Series[0].Points[0].SetValueY(totalNum - ngNum);
                this.chartHIOKIST5520Percent.Series[0].Points[0].LegendText = $"OK：{totalNum - ngNum}";
                this.chartHIOKIST5520Percent.Series[0].Points[1].SetValueY(ngNum);
                this.chartHIOKIST5520Percent.Series[0].Points[1].LegendText = $"NG：{ngNum}";
            }
        }
        /// <summary>
        /// 初始化耐压测试数量统计饼图
        /// </summary>
        private void InitHIOKI3153PercentChart()
        {
            this.chartHIOKI3153Percent.DoubleBufferredChart(true);
            this.chartHIOKI3153Percent.Series[0].Points.Clear();
            this.chartHIOKI3153Percent.Series[0].Points.Add(new System.Windows.Forms.DataVisualization.Charting.DataPoint(0, 0));
            this.chartHIOKI3153Percent.Series[0].Points[0].LegendText = "OK";
            this.chartHIOKI3153Percent.Series[0].Points[0].Color = Color.Green;
            this.chartHIOKI3153Percent.Series[0].Points[0].LabelForeColor = Color.White;
            this.chartHIOKI3153Percent.Series[0].Points.Add(new System.Windows.Forms.DataVisualization.Charting.DataPoint(1, 0));
            this.chartHIOKI3153Percent.Series[0].Points[1].LegendText = "NG";
            this.chartHIOKI3153Percent.Series[0].Points[1].Color = Color.Red;
            this.chartHIOKI3153Percent.Series[0].Points[1].LabelForeColor = Color.White;
            this.chartHIOKI3153Percent.Series[0].CustomProperties = "PieLabelStyle = Outside";
            this.chartHIOKI3153Percent.Series[0]["PieLineColor"] = "White";
        }
        /// <summary>
        /// 显示耐压测试数量
        /// </summary>
        private void ShowHIOKI3153Percent()
        {
            if (this.chartHIOKI3153Percent.InvokeRequired)
            {
                this.chartHIOKI3153Percent.Invoke(new Action(() => { ShowHIOKI3153Percent(); }));
            }
            else
            {
                var ngNum = this.mProductData.PressTestNGNum;
                var totalNum = this.mProductData.PressTestNum;
                this.chartHIOKI3153Percent.Series[0].Points[0].SetValueY(totalNum - ngNum);
                this.chartHIOKI3153Percent.Series[0].Points[0].LegendText = $"OK：{totalNum - ngNum}";
                this.chartHIOKI3153Percent.Series[0].Points[1].SetValueY(ngNum);
                this.chartHIOKI3153Percent.Series[0].Points[1].LegendText = $"NG：{ngNum}";
            }
        }
        /// <summary>
        /// 数量统计
        /// </summary>
        private ProductCountExcuteEntity mProductData = new ProductCountExcuteEntity();
        private object LOCK_READ_PRODUCT_DATA = new object();
        /// <summary>
        /// 从PLC中读取数据统计值
        /// </summary>
        private void ReadProductCountThread()
        {
            new Thread(() =>
            {
                while (GlobalStatus.PROGRAM == EAppStatus.RUN)
                {
                    try
                    {
                        lock (LOCK_READ_PRODUCT_DATA)
                        {
                            this.mProductData = CommonHelper.GetJson(PluginManager.Instance.Excute(PluginParam.Instance().GetPluginParam("App", "PRODUCTCOUNT_PLC")), new ProductCountExcuteEntity());
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                    Thread.Sleep(1000);
                }
            })
            { IsBackground = true }.Start();
        }
        #region PLC 参数定时存储
        private bool mNeedSave = true;
        private int mLastHour = -1;
        /// <summary>
        /// 开启PLC参数定时存储
        /// 打开上位机会保存一次
        /// </summary>
        private void StartPLCParamtersSaveThread()
        {
            new Thread(() =>
            {
                while (GlobalStatus.PROGRAM == EAppStatus.RUN)
                {
                    if (APPInstance.IsPLCConnected)
                    {
                        var hour = DateTime.Now.Hour;
                        if (this.mLastHour == -1 || (((hour == 8) || (hour == 20)) && this.mNeedSave))
                        {
                            SavePLCParameters();
                            this.mLastHour = hour;
                            this.mNeedSave = false;
                        }
                        if (hour == 7 || hour == 19)
                        {
                            this.mNeedSave = true;
                        }
                    }
                    Thread.Sleep(1000);
                }
            })
            { IsBackground = true }.Start();
        }
        private void SavePLCParameters()
        {
            //读配置文件
            //转换
            //读PLC
            //保存
            PluginManager.Instance.Excute(PluginParam.Instance().GetPluginParam("PLCTask", "PLCTASK_READ_PARAMS"));
        }
        #endregion

    }
}
